﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using SolutionExtender.AppCode;
using SolutionExtender.Interfaces;

namespace McTools.SolutionExtender.DuplicateDetectionRulePlugin
{
    public partial class DuplicateDetectionRuleControl : UserControl, IExportControl
    {
        #region Variables

        /// <summary>
        /// Microsoft Dynamics CRM 2011 Organization service
        /// </summary>
        private readonly IOrganizationService _service;

        /// <summary>
        /// Indicates if this control found rules
        /// </summary>
        private bool _hasData;

        #endregion Variables

        #region Constructor

        /// <summary>
        /// Initializes a new instance of class DuplicateDetectionRuleControl
        /// </summary>
        /// <param name="service">Microsoft Dynamics CRM 2011 Organization service</param>
        public DuplicateDetectionRuleControl(IOrganizationService service)
        {
            _service = service;
            InitializeComponent();
        }

        #endregion Constructor

        #region Methods

        /// <summary>
        /// Loads list of rules
        /// </summary>
        private void DuplicateDetectionRuleControlLoad(object sender, EventArgs e)
        {
            var items = new List<ListViewItem>();

            var qe = new QueryExpression("duplicaterule") { ColumnSet = new ColumnSet(true) };

            foreach (var rule in _service.RetrieveMultiple(qe).Entities)
            {
                var item = new ListViewItem(rule["name"].ToString());
                item.SubItems.Add(rule["baseentityname"].ToString());
                item.SubItems.Add(rule["matchingentityname"].ToString());
                item.Tag = rule.Id;

                items.Add(item);
            }

            if (items.Count() == 0)
            {
                _hasData = false;
                lvItems.Visible = false;
                pnlNoItems.Visible = true;
            }
            else
            {
                _hasData = true;
                pnlNoItems.Visible = false;
                lvItems.Items.AddRange(items.ToArray());
            }
        }

        /// <summary>
        /// Gets a Xml list of selected rules
        /// </summary>
        /// <returns></returns>
        public XmlNodeList GetSelectedItems()
        {
            if (lvItems.SelectedItems.Count == 0 && _hasData)
            {
                pnlError.Visible = true;
                return null;
            }

            pnlError.Visible = false;
            var stringifiedXml = new StringBuilder();
            stringifiedXml.Append("<Root>");

            foreach (ListViewItem item in lvItems.SelectedItems)
            {
                // Retrieve duplicate detection rule
                var rule = _service.Retrieve("duplicaterule", (Guid)item.Tag, new ColumnSet(true));

                // Retrieve conditions for this rule
                var qba = new QueryByAttribute("duplicaterulecondition");
                qba.Attributes.Add("regardingobjectid");
                qba.Values.Add((Guid)item.Tag);
                qba.ColumnSet = new ColumnSet(true);

                var conditions = _service.RetrieveMultiple(qba);

                var tempDoc = new XmlDocument();
                tempDoc.LoadXml(BuildReturnedString(rule, conditions));

                stringifiedXml.Append(tempDoc.DocumentElement.OuterXml);
            }

            stringifiedXml.Append("</Root>");

            var doc = new XmlDocument();
            doc.LoadXml(stringifiedXml.ToString());

            return doc.DocumentElement.ChildNodes;
        }

        /// <summary>
        /// Build a xml serialized string with rule and conditions
        /// </summary>
        /// <param name="rule">Duplicate detection rule</param>
        /// <param name="conditions">Duplicate detection conditions</param>
        /// <returns>Xml serialized string</returns>
        private string BuildReturnedString(Entity rule, EntityCollection conditions)
        {
            var ddRule = new DuplicateDetectionRule
            {
                RecordId = chkExportWithId.Checked ? rule.Id : Guid.Empty,
                BaseEntityName = rule["baseentityname"].ToString(),
                Description = rule.Contains("description") ? rule["description"].ToString() : "",
                IsCaseSensitive = (bool)rule["iscasesensitive"],
                MatchingEntityName = rule["matchingentityname"].ToString(),
                ExcludeInactiveRecords = rule.Contains("excludeinactiverecords") && (bool)rule["excludeinactiverecords"],
                Name = rule["name"].ToString(),
                Conditions = new List<DuplicateDetectionCondition>()
            };

            foreach (var condition in conditions.Entities)
            {
                ddRule.Conditions.Add(new DuplicateDetectionCondition
                {
                    BaseAttributeName = condition["baseattributename"].ToString(),
                    MatchingAttributeName = condition["matchingattributename"].ToString(),
                    OperatorCode = (OptionSetValue)condition["operatorcode"],
                    OperatorParam = condition.Contains("operatorparam") ? (int)condition["operatorparam"] : 0,
                    IgnoreBlankValues = condition.Contains("ignoreblankvalues") && (bool)condition["ignoreblankvalues"]
                });
            }

            return XmlSerializerHelper.Serialize(ddRule);
        }

        #endregion Methods

        #region Handlers

        private void LvItemsColumnClick(object sender, ColumnClickEventArgs e)
        {
            lvItems.Sorting = lvItems.Sorting == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;

            lvItems.ListViewItemSorter = new ListViewItemComparer(e.Column, lvItems.Sorting);
        }

        #endregion Handlers
    }
}
